home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 May / macformat-024.iso / Shareware City / Developers / TurboTCP 2.1 / TurboTCP core / CTCPEndpoint.cp < prev    next >
Encoding:
Text File  |  1995-01-18  |  22.3 KB  |  877 lines  |  [TEXT/MMCC]

  1. //
  2. // CTCPEndpoint.cp
  3. //
  4. //    TurboTCP library
  5. //    TCP generic protocol interpreter
  6. //
  7. //    Copyright © 1993-95, FrostByte Design / Eric Scouten
  8. //
  9.  
  10. #include "CTCPEndpoint.h"
  11.  
  12. #include "CTCPDriver.h"
  13. #include "CTCPResolverCall.h"
  14. #include "CTCPStream.h"
  15.  
  16. #include <string.h>
  17.  
  18.  
  19. #if TurboTCP_TCL
  20.     #include "CDecorator.h"
  21.     #include "CError.h"
  22.     #include "Constants.h"
  23.     #include "Global.h"
  24.     #include "TBUtilities.h"
  25.     #include "TCLUtilities.h"
  26.  
  27.     #define ConcatPStr ConcatPStrings
  28.     #define CopyPStr CopyPString
  29.  
  30.     extern CDecorator*    gDecorator;
  31.     extern CError*        gError;
  32.  
  33.     TCL_DEFINE_CLASS_M0(CTCPEndpoint);
  34. #endif
  35.  
  36. #if TurboTCP_PP
  37.     #include "String_Utils.h"
  38.     #include "UWindows.h"
  39. #endif
  40.  
  41.  
  42.  
  43. //***********************************************************
  44. //
  45. // Shortcut macros for session status information.
  46. //
  47.  
  48. #define sessionOpen (cState >= strSYNReceived) && (cState <= strTimeWait)
  49. #define sessionOpening (cState >= strListen) && (cState <= strSYNSent)
  50. #define sessionClosing (cState >= strFINWait1) && (cState <= strTimeWait)
  51.  
  52.  
  53. //***********************************************************
  54.  
  55. CTCPEndpoint::CTCPEndpoint
  56.     (unsigned short    theDefaultPort,            // default IP port number (the only required parameter)
  57.     unsigned long        recBufferSize,            // size of receive buffer to create
  58.     unsigned short    autoReceiveSize,        // number of entries in RDS for auto receive
  59.     unsigned short    autoReceiveNum,        // number of auto-receive calls to issue at once
  60.     Boolean            doUseCName)            // true to get canonical name of remote host
  61.                                         //    whenever possible
  62.  
  63. {
  64.  
  65.     // blank out the usual variables
  66.     
  67.     itsStream = nil;
  68.     itsResolver = nil;
  69.     pendingOpenByName = closeAndQuit = false;
  70.     actualPort = defaultPort = theDefaultPort;
  71.     hostCName[0] = '\0';
  72.     useCName = doUseCName;
  73.     goAwayOnClose = false;
  74.     showFileName = true;
  75.     showHostName = true;
  76.     untitledNumber = 0;
  77.     localPort = 0;
  78.  
  79.  
  80.     // create a TCP stream
  81.  
  82.     Try_ {
  83.         itsStream = new CTCPStream(*this, recBufferSize, autoReceiveSize, autoReceiveNum);
  84.         itsResolver = new CTCPResolverCall(*this);
  85.     }
  86.     
  87.     Catch_(err) {
  88.         if (itsStream)
  89.             itsStream->Dispose();
  90.         itsStream = nil;
  91.         if (itsResolver)
  92.             itsResolver->Dispose();
  93.         itsResolver = nil;
  94.         ThrowSame_;
  95.     }
  96.     
  97.     EndCatch_;
  98.     
  99. }
  100.  
  101.  
  102. //***********************************************************
  103.  
  104. CTCPEndpoint::~CTCPEndpoint()
  105.  
  106. {
  107.     if (itsStream)
  108.         itsStream->Dispose();
  109.     if (itsResolver)
  110.         itsResolver->Dispose();
  111. }
  112.  
  113.  
  114. // -- opening/closing session --
  115.  
  116. //***********************************************************
  117.  
  118. void CTCPEndpoint::OpenUserHost
  119.     (char*            theHostName,            // the host name (and optional port#) string
  120.     unsigned short    theDefaultPort,            // the default port number
  121.     Boolean            allowPortChange)        // true to allow port number overrides
  122.  
  123.     // Open a connection to the host named by the string. Hostname may be either dotted
  124.     // decimal notation or a DNS name. A port number may be specified at the end of the
  125.     // hostname (separated by a single space) if the caller permits it.
  126.  
  127. {
  128.     Str255            portNumStr;
  129.     long                newPortNum = 0;
  130.     register char*    s;
  131.     register char*    d;
  132.     register short    i;
  133.  
  134.  
  135.     // ensure that there is a host to open
  136.     
  137.     if (*theHostName == '\0') {
  138.         HandleOpenFailed(nameSyntaxErr);
  139.         return;
  140.     }
  141.  
  142.  
  143.     // parse for port number
  144.     
  145.     pendingPortNumber = theDefaultPort;
  146.     if (allowPortChange) {
  147.         s = theHostName;
  148.         d = (char*) &hostCName;
  149.         while ((*s != ' ') & (*s != '\0'))
  150.             *d++ = *s++;
  151.         *d = '\0';
  152.         if (*s == ' ') {
  153.             d = (char*) &portNumStr;
  154.             i = -1;
  155.             while (*s != '\0')
  156.                 *d++ = *s++, i++;
  157.             portNumStr[0] = (char) i;
  158.             if (i > 0)
  159.                 ::StringToNum(portNumStr, &newPortNum);
  160.         }
  161.     }
  162.     else
  163.         ::BlockMoveData(theHostName, &hostCName, 255);
  164.     
  165.     if (newPortNum != 0)
  166.         pendingPortNumber = newPortNum;
  167.  
  168.  
  169.     // issue resolver command
  170.     
  171.     pendingOpenByName = true;
  172.     actualPort = pendingPortNumber;
  173.     itsResolver->DoStrToAddr((char*) &hostCName);
  174.     
  175. }
  176.  
  177.  
  178. //***********************************************************
  179.  
  180. void CTCPEndpoint::OpenHost
  181.     (unsigned long    remoteHostIP,            // the remote host’s address
  182.     unsigned short    remoteHostPort)        // the remote host’s port number
  183.  
  184.     // Open a connection to the host named by the IP address and port number specified.
  185.     // This routine provides a way to bypass the DNR when opening connections. If the
  186.     // doUseCName option was specified when the object was constructed, this method will
  187.     // issue a DNR call to obtain the remote host’s canonical name.
  188.  
  189. {
  190.  
  191.     // open the connection
  192.     
  193.     pendingOpenByName = true;
  194.     itsStream->OpenConnection(false, remoteHostIP, remoteHostPort, localPort);
  195.  
  196.  
  197.     // set window title to dotted IP address until we can get the canonical name
  198.  
  199.     itsResolver->DoAddrToStr(remoteHostIP, hostCName);
  200.     StateChanged();
  201.  
  202.  
  203.     // if desired, get the canonical name
  204.     
  205.     if (useCName) {
  206.         itsResolver->DoAddrToName(hostAddress);
  207.         pendingOpenByName = true;
  208.     }
  209.  
  210. }
  211.  
  212.  
  213. //***********************************************************
  214.  
  215. void CTCPEndpoint::Listen
  216.     (unsigned long    remoteHostIP,            // the remote host’s address
  217.     unsigned short    remoteHostPort)        // the remote host’s port number
  218.  
  219.     // Initiate a “passive open” command. Wait for a remote host to attempt to connect to this
  220.     // machine. If the connection is to come from a specific host, the host’s IP address must be
  221.     // specified and the port number may be specified. If the connection may come from any host,
  222.     // both the IP address and port number must be left blank.
  223.  
  224. {
  225.     pendingOpenByName = true;
  226.     itsStream->OpenConnection(true, remoteHostIP, remoteHostPort, localPort);
  227. }
  228.  
  229.  
  230. //***********************************************************
  231.  
  232. Boolean CTCPEndpoint::LocalClose
  233.     (Boolean quitting)                        // true if the application is quitting
  234.  
  235.     // Use this method when the user clicks the close box, or your application is done with
  236.     // this session. Ensures that the TCP stream is gracefully closed. If not quitting, delays
  237.     // closure until MacTCP says the stream has been terminated. Note that this method
  238.     // has the same interface as TCL’s CDirector::Close.
  239.  
  240.     // Returns false if close/quit should be aborted.
  241.  
  242.     // This method is not called by the CTCPEndpoint class and need not be overriden.
  243.  
  244. {
  245.     Boolean            hadSessionOpen;
  246.     unsigned short    cState;
  247.  
  248.  
  249.     // if session is open, give time for session to close
  250.     
  251.     if (itsStream) {
  252.         cState = itsStream->ConnectionState();
  253.         hadSessionOpen = sessionOpen;
  254.         if (sessionOpen)
  255.             itsStream->Close();
  256.         if (sessionOpening)
  257.             itsStream->Abort();
  258.     }
  259.     else
  260.         hadSessionOpen = false;
  261.  
  262.  
  263.     // close the document – maybe?
  264.     
  265.     return quitting || !hadSessionOpen || !goAwayOnClose;
  266.  
  267. }
  268.  
  269.  
  270. //***********************************************************
  271.  
  272. Boolean CTCPEndpoint::SessionEstablished()
  273.  
  274.     // Returns true if a TCP session is currently established and ready for data.
  275.  
  276. {
  277.     if (itsStream)
  278.         return (itsStream->ConnectionState() == strEstablished);
  279.     else
  280.         return false;
  281. }
  282.  
  283.  
  284. // -- sending data --
  285.  
  286. //***********************************************************
  287.  
  288. void CTCPEndpoint::SendBfrCpy
  289.     (const void*        theData,            // the data to send
  290.     unsigned short    theDataSize)        // number of bytes at this address
  291.  
  292.     // Send bytes to the TCP stream. Copies the data to a buffer which can persist beyond the
  293.     // method or object which generated the data.
  294.  
  295. {
  296.     itsStream->SendBfrCpy(theData, theDataSize);
  297. }
  298.  
  299.  
  300. //***********************************************************
  301.  
  302. void CTCPEndpoint::SendBfrNoCpy
  303.     (const void*        theData,                    // the data to send
  304.     unsigned short    theDataSize,                // number of bytes to send
  305.     Boolean            disposeWhenDone,            // true to dispose of the buffer (DisposePtr)
  306.                                             //    when completed (only if this pointer was
  307.                                             //    allocated as a pointer, not a handle deref)
  308.     Boolean            notifyWhenDone)            // true to notify the endpoint object
  309.                                             //    when completed (via HandleDataSent or
  310.                                             //    HandleSendFailed)
  311.  
  312.     // Send bytes to the TCP stream. Does not copy the data. The caller is responsible for
  313.     // ensuring that the data are available until the call is completed. You may detect the safe
  314.     // transmittal of your data by overriding the HandleDataSent() method and comparing
  315.     // pointers. You may also request that the data be disposed (using the DisposePtr routine)
  316.     // when the call completes by setting disposeWhenDone to true.
  317.  
  318. {
  319.     itsStream->SendBfrNoCpy(theData, theDataSize, disposeWhenDone, notifyWhenDone);
  320. }
  321.  
  322.  
  323. //***********************************************************
  324.  
  325. void CTCPEndpoint::SendChar
  326.     (const char theChar)                    // the character to send
  327.  
  328.     // Send a single character to the remote host.
  329.  
  330. {
  331.     SendBfrCpy(&theChar, 1);
  332. }
  333.  
  334.  
  335. //***********************************************************
  336.  
  337. void CTCPEndpoint::SendCString
  338.     (const char* theString)                // the string to send
  339.  
  340.     // Send a C string to the remote host (not including the /0 byte).
  341.  
  342. {
  343.     SendBfrCpy(theString, strlen((char*) theString));
  344. }
  345.  
  346.  
  347. //***********************************************************
  348.  
  349. void CTCPEndpoint::SendPString
  350.     (const unsigned char* theString)        // the string to send
  351.  
  352.     // Send a Pascal string to the TCP stream (not including the length byte).
  353.  
  354. {
  355.     SendBfrCpy((char*) theString + 1, theString[0]);
  356. }
  357.  
  358.  
  359. //***********************************************************
  360.  
  361. void CTCPEndpoint::SetNextPush()
  362.  
  363.     // The next data will be sent with the “push” flag set.
  364.  
  365. {
  366.     itsStream->SetNextPush();
  367. }
  368.  
  369.  
  370. //***********************************************************
  371.  
  372. void CTCPEndpoint::SetNextUrgent()
  373.  
  374.     // The next data will be sent with the “urgent” flag set.
  375.  
  376. {
  377.     itsStream->SetNextUrgent(false);
  378. }
  379.  
  380.  
  381. //***********************************************************
  382. //
  383. // Stream-like manipulators for CTCPEndpoint
  384. //    
  385.  
  386. CTCPEndpoint& endl(CTCPEndpoint& ep)                // send end-of-line characters
  387. {
  388.     ep.SendChar('\r');
  389.     return ep;
  390. }
  391.  
  392. CTCPEndpoint& local_IP(CTCPEndpoint& ep)            // send local IP address in dotted IP format
  393. {
  394.     char ip_addr[16];
  395.     UTurboTCP::DoAddrToStr(ep.GetLocalHostIP(), ip_addr);
  396.     ep << ip_addr;
  397.     return ep;
  398. }
  399.  
  400. CTCPEndpoint& remote_IP(CTCPEndpoint& ep)            // send remote IP address in dotted IP format
  401. {
  402.     char ip_addr[16];
  403.     UTurboTCP::DoAddrToStr(ep.GetRemoteHostIP(), ip_addr);
  404.     ep << ip_addr;
  405.     return ep;
  406. }
  407.  
  408. CTCPEndpoint& push(CTCPEndpoint& ep)                // send next data with “push” flag set
  409. {
  410.     ep.SetNextPush();
  411.     return ep;
  412. }
  413.  
  414. CTCPEndpoint& urgent(CTCPEndpoint& ep)                // send next data with “urgent” flag set
  415. {
  416.     ep.SetNextUrgent();
  417.     return ep;
  418. }
  419.  
  420.  
  421.  
  422. //***********************************************************
  423. //
  424. // Configuration methods
  425. //
  426. //    Use these methods to set various IP parameters for the next connection built on this
  427. //    endpoint. If a session has been opened already on this endpoint, these methods will have
  428. //    no effect on the current session.
  429. //
  430.  
  431. void CTCPEndpoint::SetDefaultPort(unsigned short newDefaultPort)        // set default remote host port
  432.     { defaultPort = newDefaultPort; }
  433. void CTCPEndpoint::SetLocalHostPort(unsigned short newLocalPort)        // set a new local host port for next connection
  434.     { localPort = newLocalPort; }
  435. void CTCPEndpoint::SetOpenTimeout(unsigned short openMaxSeconds)        // max time to establish session for next connection
  436.     { itsStream->SetULPTimeoutValue(openMaxSeconds); }
  437. void CTCPEndpoint::SetListenTimeout(unsigned short openMaxSeconds)    // max time to wait for passive connection
  438.     { itsStream->SetCommandTimeout((short) openMaxSeconds); }
  439. void CTCPEndpoint::SetTypeOfService(Boolean lowDelay,                    // set type of service for next connection
  440.         Boolean highThroughput, Boolean highReliability)
  441.     { itsStream->SetTypeOfService((lowDelay ? 0x01 : 0) |
  442.         (highThroughput ? 0x02 : 0) | (highReliability ? 0x04 : 0)); }
  443. void CTCPEndpoint::SetPrecedence(TCPPrecedence newPrecedence)            // set precedence for next connection
  444.     { itsStream->SetPrecedence((short) newPrecedence); }
  445. void CTCPEndpoint::SetDontFragment(Boolean newDontFragment)            // set/clear don’t fragment for next connection
  446.     { itsStream->SetDontFrag((short) newDontFragment); }
  447. void CTCPEndpoint::SetTimeToLive(unsigned short newTimeToLive)        // maximum hop count for IP connection
  448.     { itsStream->SetTimeToLive(newTimeToLive); }
  449. void CTCPEndpoint::SetSecurity(unsigned short newSecurity)            // security flag
  450.     { itsStream->SetSecurity(newSecurity); }
  451.  
  452.  
  453. //***********************************************************
  454. //
  455. // Selectors
  456. //
  457. //    Use these methods to get information on the current endpoint and connection.
  458. //
  459.  
  460. void CTCPEndpoint::GetRemoteHostName(char* hostStringBfr)                // get the name of the remote host machine
  461.     { ::BlockMoveData(hostCName, hostStringBfr, strlen(hostCName)); }
  462. unsigned long CTCPEndpoint::GetRemoteHostIP()
  463.     { return hostAddress; }
  464. unsigned short CTCPEndpoint::GetRemoteHostPort()
  465.     { return actualPort; }
  466. unsigned long CTCPEndpoint::GetLocalHostIP()
  467.     { return UTurboTCP::GetLocalIPAddr(); }
  468. unsigned short CTCPEndpoint::GetLocalHostPort()
  469.     { return localPort; }
  470. unsigned short CTCPEndpoint::GetDefaultPort()
  471.     { return defaultPort; }
  472.  
  473.  
  474. // -- state change notifications --
  475.  
  476. //***********************************************************
  477.  
  478. void CTCPEndpoint::RemoteClose()                // protected method
  479.  
  480.     // This method is called when the remote host closes or aborts a session. Override this
  481.     // to ensure that your windows are closed or the user is somehow notified. (Be sure to
  482.     // call this method as well.)
  483.  
  484. {
  485.     unsigned short cState;
  486.  
  487.  
  488.     // be sure to acknowledge the remote host’s intention to close
  489.  
  490.     if (itsStream) {
  491.         cState = itsStream->ConnectionState();
  492.         if (sessionOpen)
  493.             itsStream->Close();
  494.         if (sessionOpening)
  495.             itsStream->Abort();
  496.     }
  497. }
  498.  
  499.  
  500. //***********************************************************
  501.  
  502. void CTCPEndpoint::StateChanged()                // protected method
  503.  
  504.     // Called by other methods when the connection state changes (i.e. opens, aborts, or closes).
  505.     // Builds a new window title, then calls the SetWindowTitle() method to signal that the
  506.     // window’s title should be changed. 
  507.  
  508. {
  509.     Str255    fileStr = "\p";
  510.     Str255    hostStr = "\p";
  511.     Str255    tempStr  = "\p";
  512.     Boolean    sessionReady = SessionEstablished();
  513.  
  514.  
  515.     // build document name string (if requested)
  516.     
  517.     if (showFileName) {
  518.     
  519.         // see if there’s a default name for this file
  520.         
  521.         GetFileName(fileStr);
  522.  
  523.         // if there’s no title, build an untitled-__ name
  524.         
  525.         if (fileStr[0] == '\0') {
  526.             if (!untitledNumber) {
  527.             
  528.                 // need to assign an untitled number: use class library’s default method
  529.                 
  530.                 #if TurboTCP_TCL
  531.                     untitledNumber = gDecorator->GetWCount();
  532.                 #else
  533.                 #if TurboTCP_PP
  534.                 
  535.                     // try default name “untitled”
  536.                     
  537.                     ::GetIndString(fileStr, STR__WindowStrings, Wstr_UntitledNoNumber);
  538.  
  539.                     // if an existing window has the current name; increment counter and try again
  540.  
  541.                     while (UWindows::FindNamedWindow(fileStr) != nil) {
  542.                         untitledNumber++;
  543.                         ::GetIndString(fileStr, STR__WindowStrings, Wstr_Untitled);
  544.                         ::NumToString(untitledNumber, tempStr);
  545.                         ConcatPStr(fileStr, tempStr);
  546.                     }
  547.                     if (untitledNumber == 0)
  548.                         untitledNumber = -1;
  549.                     
  550.                 #else
  551.                     #error Don't know how to build untitled numbers
  552.                 #endif
  553.                 #endif
  554.             }
  555.  
  556.             // now we have a number, use it
  557.             
  558.             ::GetIndString(fileStr, STR__WindowStrings, Wstr_Untitled);
  559.             if (untitledNumber != -1) {
  560.                 ::NumToString(untitledNumber, tempStr);
  561.                 ConcatPStr(fileStr, tempStr);
  562.             }
  563.         }
  564.     }
  565.  
  566.  
  567.     // build host name string
  568.  
  569.     if (showHostName) {
  570.         if (!hostCName[0])
  571.             ::GetIndString(hostStr, STR__WindowStrings, Wstr_NoSession);
  572.         else {
  573.             
  574.             if (!sessionReady)                            // left “(” if not ready
  575.                 ::GetIndString(hostStr, STR__WindowStrings, Wstr_NotReadyPrefix);
  576.                 
  577.             ::BlockMoveData(&hostCName, &tempStr, 255);    // host name, minus trailing “.”
  578.             CtoPstr((char*) &tempStr);
  579.             if (tempStr[tempStr[0]] == '.')
  580.                 tempStr[0]--;
  581.             ConcatPStr(hostStr, tempStr);
  582.             
  583.             if (actualPort != defaultPort) {                    // port number if non-standard
  584.                 ::GetIndString(tempStr, STR__WindowStrings, Wstr_PortDelimiter);
  585.                 ConcatPStr(hostStr, tempStr);
  586.                 ::NumToString(actualPort, tempStr);
  587.                 ConcatPStr(hostStr, tempStr);
  588.             }
  589.             
  590.             if (!sessionReady) {                            // right “)” if not ready
  591.                 ::GetIndString(tempStr, STR__WindowStrings, Wstr_NotReadySuffix);
  592.                 ConcatPStr(hostStr, tempStr);
  593.             }
  594.             
  595.         }
  596.         
  597.         if (showFileName) {                                // “ : ” between file & host name
  598.             ::GetIndString(tempStr, STR__WindowStrings, Wstr_Separator);
  599.             ConcatPStr(fileStr, tempStr);
  600.         }
  601.         ConcatPStr(fileStr, hostStr);
  602.     }
  603.  
  604.  
  605.     // set the title
  606.  
  607.     if (showFileName || showHostName)                        // if neither file nor hostname are requested,
  608.         SetWindowTitle(fileStr);                            //    assume subclass will specify window titles                    
  609.  
  610. }
  611.  
  612.  
  613. // -- error handling --
  614.  
  615. //***********************************************************
  616.  
  617. short CTCPEndpoint::TCPErrorAlert    // protected method
  618.     (OSErr    err,                    // the error number
  619.     long        message,                // message code (same as for ErrorAlert, see <TCLUtilities.cp>
  620.     short    alertID,                // the ALRT/DITL resources to use
  621.     short    parm3)                // the number to plug into ^3 in the error box
  622.  
  623.     // Display a customized message to indicate to the user that the connection failed.
  624.     // This routine is copied from the TCL’s routine ErrorAlert.
  625.  
  626. {
  627.     Str255    errStr;
  628.     Str255    hostStr;
  629.     Str63    numStr;
  630.     Str63    numStr3;
  631.     short    strIndex, strID;
  632.  
  633.     //! need to check to see if the rest of this works w/o TCL
  634.  
  635.     // silence any further messages
  636.     
  637.     #if TurboTCP_TCL
  638.         gLastError = kSilentErr;
  639.     #endif
  640.  
  641.  
  642.     // see if anyone filled in the message field
  643.     
  644.     errStr[0] = 0;
  645.     strIndex = message & 0xFFFF;
  646.     
  647.     if (strIndex > 0) {
  648.         strID = message >> 16 & 0xFFFF;
  649.         if (strID == 0)
  650.             #if TurboTCP_TCL
  651.                 strID = STR_TCLfailMsgs;            // use built-in messages
  652.             #else
  653.                 strID = 0;                        //! TEMPORARY: hmmm... what to do
  654.             #endif
  655.         else
  656.             #if TurboTCP_TCL
  657.                 strID += kUserFailMsgBase;        // use user’s message STR#
  658.             #else
  659.                 strID = 0;                        //! TEMPORARY: hmmm… what to do
  660.             #endif
  661.         ::GetIndString(errStr, strID, strIndex);
  662.     }
  663.  
  664.  
  665.     // if still no message, check for 'Estr' resource
  666.         
  667.     if (errStr[0] == 0) {
  668.         StringHandle strH;
  669.          
  670.         strH = (StringHandle) ::GetResource('Estr', err);
  671.         if (!strH)
  672.             #if TurboTCP_TCL
  673.                  strH = ::GetString(STRosError2);
  674.              #else
  675.                  strH = nil;                            //! TEMPORARY: not sure what to do
  676.              #endif
  677.          if (strH)
  678.              CopyPStr(*strH, errStr);
  679.     }
  680.  
  681.  
  682.     // convert Mac error# and user’s host name to strings
  683.             
  684.     ::NumToString(err, numStr);
  685.     ::NumToString(parm3, numStr3);
  686.  
  687.     ::BlockMoveData(&hostCName, &hostStr, 255);
  688.     CtoPstr((char*) &hostStr);
  689.     if (hostStr[hostStr[0]] == '.')
  690.         hostStr[0]--;
  691.  
  692.     ::ParamText(errStr, numStr, hostStr, numStr3);
  693.  
  694.  
  695.     // avoid infinite recursion in error handling by specifically
  696.     //    testing if the ALRT and DITL resources we need are there
  697.         
  698.     if ((::GetResource('ALRT', alertID) == nil) || (::GetResource('DITL', alertID) == nil)) {
  699.         #if TurboTCP_TCL
  700.         if (gError)
  701.             gError->MissingResources();
  702.         else
  703.         #endif
  704.             ::ExitToShell();            // nothing else we can do...
  705.     }
  706.    
  707.    
  708.        // show the error alert
  709.  
  710.     #if TurboTCP_TCL
  711.         PositionDialog('ALRT', alertID);            //! TEMPORARY: aarrrgghh!
  712.     #endif
  713.     ::InitCursor();
  714.     return ::StopAlert(alertID, nil);
  715.  
  716. }
  717.  
  718.  
  719. // -- TCP/DNR notification routines -- 
  720.  
  721. //***********************************************************
  722.  
  723. void CTCPEndpoint::HandleClosing        // protected method
  724.     (Boolean remoteClosing)            // true if close initiated by remote host
  725.  
  726.     // Respond to notification that the session is being closed.
  727.  
  728. {
  729.     StateChanged();
  730.     if (remoteClosing)
  731.         RemoteClose();
  732. }
  733.  
  734.  
  735. //***********************************************************
  736.  
  737. void CTCPEndpoint::HandleOpened()        // protected method
  738.  
  739.     // Respond to successful completion of a TCPPassiveOpen or TCPActiveOpen command.
  740.  
  741. {
  742.     actualPort = itsStream->itsRemotePort;
  743.     StateChanged();
  744. }
  745.  
  746.  
  747. //***********************************************************
  748.  
  749. void CTCPEndpoint::HandleOpenFailed        // protected method
  750.     (OSErr theResultCode)                // the reason for failure
  751.  
  752. {
  753.     TCPErrorAlert(theResultCode, 0L, ALRT_TCPOpenFailed, 1);
  754.     RemoteClose();
  755.     ThrowOSErr_(0);    
  756. }
  757.  
  758.  
  759. //***********************************************************
  760.  
  761. void CTCPEndpoint::HandleTCPError        // protected method
  762.     (OSErr    theResultCode,            // the result code
  763.     short    theCsCode)            // the TCP command number that failed
  764.  
  765.     // Respond to failure of a TCP command that was not expected. Default method displays a
  766.     // dialog, but takes no other action.
  767.  
  768. {
  769.     TCPErrorAlert(theResultCode, 0L, ALRT_TCPUnexpError, theCsCode);
  770. }
  771.  
  772.  
  773. //***********************************************************
  774.  
  775. void CTCPEndpoint::HandleTerminated        // protected method
  776.     (TCPTerminReason    terminReason,        // reason for termination (see TCP dev guide, p93)
  777.     Boolean            aboutToDispose)    // true if TCP stream will now dispose of itself
  778.  
  779.     // Respond to session termination event.
  780.  
  781. {
  782.  
  783.     // display error alert unless due to normal closure
  784.     
  785.     if ((terminReason != tcpTermAbort) && (terminReason != tcpTermClose))
  786.         TCPErrorAlert(terminReason + ESTR_TerminBase, 0L, ALRT_TCPTerminated, 0);
  787.  
  788.  
  789.     // retitle window & close if requested
  790.  
  791.     StateChanged();
  792.     RemoteClose();
  793.  
  794.  
  795.     // mark TCP stream as gone if appropriate
  796.     
  797.     if (aboutToDispose)
  798.         itsStream = nil;
  799.  
  800. }
  801.  
  802.  
  803. //***********************************************************
  804.  
  805. void CTCPEndpoint::HandleStrToAddr    // protected method
  806.     (struct hostInfo* theHostInfo)        // the hostinfo record (see TCP dev guide, p70)
  807.  
  808.     // Respond to nofitication that a resolver StrToAddr call has completed. Most of this code
  809.     // is written to complete the OpenUserHost method. If OpenUserHost was issued, this method
  810.     // proceeds to establish a connection with the IP host which was named by the user.
  811.  
  812. {
  813.  
  814.     // if OpenUserHost was issued, finish the job
  815.     
  816.     if ((pendingOpenByName) && (itsStream)) {
  817.         if ((*theHostInfo).rtnCode == noErr) {
  818.  
  819.  
  820.             // success, open the connection
  821.             
  822.             hostAddress = (*theHostInfo).addr[0];
  823.             pendingOpenByName = false;
  824.             itsStream->OpenConnection(false, hostAddress, pendingPortNumber, localPort);
  825.  
  826.  
  827.             // if desired, get the canonical name
  828.             
  829.             if (useCName) {
  830.                 if ((*theHostInfo).cname[0] == 0) {
  831.                     itsResolver->DoAddrToName(hostAddress);
  832.                     pendingOpenByName = true;
  833.                 }
  834.                 else
  835.                     ::BlockMoveData(&(*theHostInfo).cname, &hostCName, 255);
  836.             }
  837.  
  838.  
  839.             // set the window title to reflect the name
  840.             
  841.             StateChanged();
  842.  
  843.         } else {
  844.  
  845.             // failed, issue alert & quit
  846.  
  847.             pendingOpenByName = false;
  848.             HandleOpenFailed((*theHostInfo).rtnCode);
  849.  
  850.         } // if (...noErr)
  851.     } // if (pendingOpenByName)
  852.     
  853. }
  854.  
  855.  
  856. //***********************************************************
  857.  
  858. void CTCPEndpoint::HandleAddrToName    // protected method
  859.     (struct hostInfo* theHostInfo)        // the hostInfo record (see TCP dev guide, p75)
  860.  
  861.     // Respond to notification that a resolver AddrToName call has completed.
  862.  
  863. {
  864.  
  865.     // if OpenUserHost was issued, grab the hostname
  866.     
  867.     if ((pendingOpenByName) && (useCName)) {
  868.         if ((*theHostInfo).rtnCode == noErr) {
  869.             pendingOpenByName = false;
  870.             if ((*theHostInfo).cname[0])
  871.                 ::BlockMoveData(&(*theHostInfo).cname, &hostCName, 255);
  872.             StateChanged();
  873.         }
  874.     }
  875.  
  876. }
  877.